package com.utility;

import okio.BufferedSink;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import com.utility.hostnameverify.OkHttpHostnameVerifier;
import com.utility.interceptor.OkHttpLoggingInterceptor;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class HttpUtility {
	private static OkHttpClient okHttpClient;
    static{
        List<Protocol> protocols = new ArrayList<Protocol>();
        protocols.add(Protocol.HTTP_1_1);
        protocols.add(Protocol.HTTP_2);
        okHttpClient = new OkHttpClient.Builder().connectTimeout(1500, TimeUnit.MILLISECONDS) // 设置连接超时
                .readTimeout(2, TimeUnit.SECONDS) // 设置读超时
                .writeTimeout(2, TimeUnit.SECONDS) // 设置写超时
                .retryOnConnectionFailure(true) // 是否自动重连
                .connectionPool(new ConnectionPool(100, 5, TimeUnit.MINUTES))
                .protocols(protocols)
                /**
                 *  addInterceptor() 添加应用拦截器
                 *  不需要担心中间过程的响应,如重定向和重试.
                 *  总是只调用一次,即使HTTP响应是从缓存中获取.
                 *  观察应用程序的初衷. 不关心OkHttp注入的头信息如: If-None-Match.
                 *  允许短路而不调用 Chain.proceed(),即中止调用.
                 *  允许重试,使 Chain.proceed()调用多次.
                 *
                 *  addNetworkInterceptor() 添加网络拦截器
                 *  能够操作中间过程的响应,如重定向和重试.
                 *  当网络短路而返回缓存响应时不被调用.
                 *  只观察在网络上传输的数据.
                 *  携带请求来访问连接.
                 */
                .addNetworkInterceptor(new OkHttpLoggingInterceptor())
                .sslSocketFactory(sslSocketFactory(), x509TrustManager())
                .hostnameVerifier(new OkHttpHostnameVerifier()).build();
        //Springboot，设置server.http2.enabled=true
        //OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory(okHttpClient);
		//RestTemplate restTemplate = new RestTemplate(okHttp3ClientHttpRequestFactory);
    }

    public static X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }
            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    public static SSLSocketFactory sslSocketFactory() {
        try {
            //信任任何链接
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }



    public static Response syncGet(String url){
        Request request = new Request.Builder().url(url).build();
        Response response = null;
        try{
            response = okHttpClient.newCall(request).execute();
            return response;
        }catch(Exception e){
            e.printStackTrace();
        }
        return response;
    }

    public static void asyncGet(String url){
        Request request = new Request.Builder().url(url).build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println(e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    System.out.println(response.body().string());
                }
            }
        });
    }

    public static Response suncPost(String url){
        RequestBody requestBody = new RequestBody() {
            @Override
            public MediaType contentType() {
                return MediaType.parse("text/x-markdown; charset=utf-8");
            }
            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.writeUtf8("I am Jdqm.");
            }
        };

        //Form表单
        //requestBody = new FormBody.Builder().add("search", "Jurassic Park").build();
        //文件
        //requestBody = RequestBody.create(new File(""),MediaType.parse("text/x-markdown; charset=utf-8"));

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Response response = null;
        try{
            response = okHttpClient.newCall(request).execute();
            return response;
        }catch(Exception e){
            e.printStackTrace();
        }
        return response;
    }

    public static void main(String[] args) throws IOException {
        String url = "https://www.baidu.com";
        System.out.println(syncGet(url).body().string());
        System.out.println(suncPost(url).body().string());
        asyncGet(url);
    }
}
